//
// Created by zhengjuping on 24-9-9.
//

#include <esp_log.h>
#include "include/GattsService.h"

#define TAG "GattsService"

GattsService::GattsService(const BleUuid &serviceUuid)
                          :_serviceUuid(serviceUuid),
                           _serviceHandle(-1),
                           _serviceId(-1){

    switch (_serviceUuid.getWidth()) {
        case BleUuid::Width::UUID_16:
            _primary_service_uuid = _serviceUuid.getUuid16();
            _primary_service_uuid_size = 2;
            break;

        case BleUuid::Width::UUID_32:
            _primary_service_uuid = _serviceUuid.getUuid32();
            _primary_service_uuid_size = 4;
            break;
    }

    auto primaryServiceCharacteristic = std::make_shared<GattCharacteristic>(
            BleUuid(BleUuid::Width::UUID_16, 0x2800),
            (uint8_t *)&_primary_service_uuid,
            _primary_service_uuid_size,
            GattCharacteristic::ResponseMethod::AUTO_RSP,
            GattCharacteristic::Properties::Read,
            GattCharacteristic::Permissions::Read);
    _characteristicsVector.push_back(primaryServiceCharacteristic);
    const esp_gatts_attr_db_t *primaryAttrDb = primaryServiceCharacteristic->getAttrDb();
    _attributeTableVector.push_back(*primaryAttrDb);
}

int32_t GattsService::addCharacteristic(const std::shared_ptr<GattCharacteristic> &characteristic,
                                        const std::shared_ptr<GattCharacteristic> &descCharacteristic) {

    uint16_t properties = characteristic->getProperties();
    auto declarationCharacteristic = std::make_shared<GattCharacteristic>(
            BleUuid(BleUuid::Width::UUID_16, 0x2803),
            (uint8_t *)&properties,
            sizeof(uint16_t),
            GattCharacteristic::ResponseMethod::AUTO_RSP,
            GattCharacteristic::Properties::Read,
            GattCharacteristic::Permissions::Read);

    _characteristicsVector.push_back(declarationCharacteristic);
    const esp_gatts_attr_db_t *declarationAttrDb = declarationCharacteristic->getAttrDb();
    _attributeTableVector.push_back(*declarationAttrDb);

    _characteristicsVector.push_back(characteristic);
    const esp_gatts_attr_db_t *attrDb = characteristic->getAttrDb();
    _attributeTableVector.push_back(*attrDb);

    if( descCharacteristic != nullptr ){
        _characteristicsVector.push_back(descCharacteristic);
        const esp_gatts_attr_db_t *descAttrDb = descCharacteristic->getAttrDb();
        _attributeTableVector.push_back(*descAttrDb);
    }

    return 0;
}

void GattsService::dump() {
    for( auto &attributeTable : _attributeTableVector ){
        ESP_LOGE(TAG, "autoRsp::%d", attributeTable.attr_control.auto_rsp);
        esp_log_buffer_hex_internal(TAG, attributeTable.att_desc.uuid_p, attributeTable.att_desc.uuid_length, ESP_LOG_WARN);
        ESP_LOGE(TAG, "perm::%d", attributeTable.att_desc.perm);
        ESP_LOGE(TAG, "max_length::%d", attributeTable.att_desc.max_length);
        esp_log_buffer_hex_internal(TAG, attributeTable.att_desc.value, attributeTable.att_desc.length, ESP_LOG_WARN);
    }
}


int32_t GattsService::characteristicReadEvent(uint16_t handle, uint8_t *p_value, uint16_t &length) {
    for( auto &characteristic : _characteristicsVector ){
        if( characteristic->getHandle() == handle ){
            characteristic->onReadEvent(p_value, length);
        }
    }
    return 0;
}

int32_t GattsService::characteristicWriteEvent(uint16_t handle, uint8_t *p_value, uint16_t length) {
    for( auto &characteristic : _characteristicsVector ){
        if( characteristic->getHandle() == handle ){
            characteristic->onWriteEvent(p_value, length);
        }
    }
    return 0;
}

int32_t GattsService::characteristicNotifyEvent(uint16_t handle, bool enable) {
    for( auto &characteristic : _characteristicsVector ){
        if( characteristic->getHandle() == handle ){
            characteristic->onNotifyStatusUpdateEvent(enable);
        }
    }
    return 0;
}

int32_t GattsService::characteristicConnectEvent(uint16_t gattsIf, uint16_t connId) {
    for( auto &characteristic : _characteristicsVector ){
        characteristic->setGattsIf(gattsIf);
        characteristic->setConnId(connId);
        characteristic->onConnectEvent();
    }
    return 0;
}

int32_t GattsService::characteristicDisconnectEvent(uint16_t gattsIf, uint16_t connId) {
    for( auto &characteristic : _characteristicsVector ){
        characteristic->setGattsIf(gattsIf);
        characteristic->setConnId(connId);
        characteristic->onDisConnectEvent();
    }
    return 0;
}


void GattsService::pushHandles(const uint16_t *handles, uint16_t numHandles) {
    if( _characteristicsVector.size() != numHandles ){
        ESP_LOGE(TAG, "characteristic size not match, characteristic size: %d, handle size: %d",
                 _characteristicsVector.size(), numHandles);
        abort();
    }

    for( int32_t i = 0; i < numHandles; i++ ){
        _characteristicsVector[i]->setHandle(handles[i]);
    }
}

const BleUuid &GattsService::getServiceUuid() const {
    return _serviceUuid;
}

const esp_gatts_attr_db_t *GattsService::getAttributeTable(uint32_t &size) const {
    size = _attributeTableVector.size();
    return _attributeTableVector.data();
}

void GattsService::setSvcId(int32_t id) {
    _serviceId = id;
}

int32_t GattsService::getSvcId() const {
    return _serviceId;
}

bool GattsService::hasHandle(uint16_t handle) {
    for( auto &characteristic : _characteristicsVector ){
        if( characteristic->getHandle() == handle ){
            return true;
        }
    }
    return false;
}




